import os
import shutil
import subprocess
import re


# 定义图标文件路径, 该图标将用于打包后的应用程序
app_icon = ".\\globals\\uni-core.png"
# 定义应用程序的唯一标识符, 用于系统识别应用
appID = "com.uni-core.app"
# 定义可执行文件的名称, 即打包后生成的应用程序文件名
exe_file = "密码管家.exe"
# 定义输出目录, 打包后的文件将存放在此目录下
output_dir = "output"
# 定义输出路径, 将输出目录和可执行文件名称组合成完整的路径
output_path = os.path.join(output_dir, exe_file)
# 是否强制忽略版本号检查, 默认为False
force_ignore_version = False


# 定义一个函数, 用于打包应用程序
def package_app():
    # 声明的全局变量, 用于存储可执行文件的名称
    global exe_file, output_path

    # 打印提示信息
    print(f"开始打包{exe_file}...")

    # 通过go fmt 命令格式化当前目录下的所有Go文件, 如果存在错误则打印错误信息并返回
    try:
        subprocess.run(["go", "fmt", "./..."], check=True)
    except subprocess.CalledProcessError as e:
        print("go fmt 格式化失败:")
        if e.stderr:
            print(e.stderr.strip())
        else:
            print("No stderr output.")
        return

    # 通过go vet 命令检查当前目录下的所有Go文件, 如果存在错误则打印错误信息并返回
    try:
        subprocess.run(["go", "vet", "./..."], check=True)
    except subprocess.CalledProcessError as e:
        print("go vet 检查失败:")
        if e.stderr:
            print(e.stderr.strip())
        else:
            print("No stderr output.")
        return

    # 检查fyne命令是否可用, 如果不可用则打印错误信息并返回
    if shutil.which("fyne") is None:
        print("fyne命令不可用, 请确保已正确安装fyne工具")
        return  # 终止程序的执行, 不执行后续代码

    # 检查main.go文件是否存在, 如果不存在则打印错误信息并返回
    if not os.path.exists("main.go"):
        print("main.go文件不存在")
        return  # 终止程序的执行, 不执行后续代码

    # 检查app_icon文件是否存在, 如果不存在则打印错误信息并返回
    if not os.path.exists(app_icon):
        print(f"图标文件不存在: {app_icon}")
        return

    # 检查output目录是否存在, 如果不存在则创建该目录
    if not os.path.exists(output_dir):
        # 创建output目录
        os.makedirs(output_dir)
        # 打印提示信息, 告知用户已创建目录
        print(f"创建目录: {output_dir}")

    # 检查output_path文件是否存在, 如果存在则删除该文件
    if os.path.exists(output_path):
        os.remove(output_path)
        print(f"删除旧的可执行文件: {output_path}")

    # 构建fyne打包命令, 指定操作系统为Windows, 以发布模式打包, 指定应用名称、图标和应用ID
    cmd = f"fyne package -os windows --release --name {exe_file} -icon {app_icon} --appID {appID}"

    # 检查当前目录是否为git仓库, 如果是构建命令并获取版本号
    if os.path.exists(".git"):
        try:
            # 获取当前git仓库的版本号
            git_version = subprocess.run(
                ["git", "describe", "--tags", "--always", "--dirty"],
                capture_output=True,
                text=True,
            ).stdout.strip()

            # 检查版本号的格式是否为语义化的 x.y.z 格式 , 如果不是则打印错误信息并返回
            if not re.match(r"^\d+\.\d+\.\d+$", git_version):
                # 如果强制忽略版本号检查, 则将版本号修建为 x.y.z 格式
                if force_ignore_version:
                    print(f"版本号格式错误: {git_version}, 强制忽略版本号检查")
                    # 获取版本号，以-分割字符串, 并取前1个部分
                    git_version = git_version.split("-")[0]
                    # 检查版本号的格式是否为语义化的 x.y.z 格式 , 如果不是则打印错误信息并返回
                    if not re.match(r"^\d+\.\d+\.\d+$", git_version):
                        print(f"版本号格式错误: {git_version}, 语义化版本格式为 x.y.z")
                        return
                    else:
                        print(f"忽略为: {git_version}")
                else:
                    print(f"版本号格式错误: {git_version}, 格式应为 x.y.z, 或先提交git")
                    return

            # 将版本号添加到打包命令中
            cmd += f" --appVersion {git_version}"
        except subprocess.CalledProcessError as e:
            print(f"获取版本号失败: {e}")
            return

    # 执行fyne打包命令
    try:
        # 执行fyne打包命令, 并等待命令执行完成
        subprocess.run(cmd, shell=True, check=True)
        # 打印提示信息, 告知用户打包命令执行成功
        print("打包命令执行成功")
    except subprocess.CalledProcessError as e:
        # 若打包命令执行失败, 打印错误信息
        print(f"打包失败: {e}")
        return

    # 移动可执行文件到output目录下
    try:
        # 根据操作系统的不同, 设置可执行文件的路径
        if os.name == "nt":
            if not exe_file.endswith(".exe"):
                exe_file += ".exe"

            if not output_path.endswith(".exe"):
                output_path += ".exe"

        # 拷贝可执行文件到output目录下
        shutil.move(exe_file, output_path)
    except Exception as e:
        print(f"拷贝文件失败: {e}")
    else:
        print(f"{exe_file} -> {output_path}")

    # 打印提示信息, 告知用户打包完成
    print(f"打包完成: {output_path}")


# 当该脚本作为主程序运行时, 调用package_app函数进行应用程序打包
if __name__ == "__main__":
    package_app()
